package server;

import java.io.IOException;

import commands.Command;
import commands.CommandException;

import core.GameParticipantRegistry;
import core.Player;

/**
 * Acts as a proxy (GoF Proxy pattern) between a GameServer and a single
 * Client. Listens for Commands from the Client, and translates the IDs found
 * in these Commands into local GameObject references.
 */
public class ClientProxy extends net.ObjectSerializer implements Runnable, net.Reactor<commands.Command>, core.GameParticipant
{
	/**
	 * Creates a ClientProxy with the given GameServer and Socket. 
	 * @param gameController The GameServer that owns the Game we're participating in
	 * @param socket A Socket connected to a Client
	 */
	public ClientProxy(GameServer gameServer, Player player, java.net.Socket socket) throws IOException
	{
		super(socket, ClientProxyReactorProxy.class, ClientProxyReactorProxy.NAME_MAPPER);
		this.gameServer = gameServer;
		this.player = player;
		dictionary.update(gameServer.getGame());
	}

	/**
	 * Listens for incoming messages on the Socket.  These messages are
	 * deserialized into Commands, which are then forwarded to the
	 * GameServer for execution.
	 */
	public void run()
	{
		// Register this thread as a maintainer of the GameController
		GameParticipantRegistry.put(this);
		try {
			reader.parse(connection.in());
		} catch (org.xml.sax.SAXException e) {
			javax.swing.JOptionPane.showMessageDialog(null,"A player has disconnected and this game will now terminate");
			gameServer.endGame(null);
			//e.printStackTrace();
		} catch (IOException e) {
			if (e.getMessage().equalsIgnoreCase("Connection reset"))
				System.err.println("Client connection was closed or reset.");
			else
				e.printStackTrace();
		}
	}

	public void react(Command command) {
		try {
			command.setPlayer(player);
			gameServer.executeCommand(command);
		} catch (CommandException e) {
			e.printStackTrace();
		}
	}

	public void sendStateUpdate(net.StateUpdate stateUpdate, Command cause) throws IOException {
		core.GameParticipant old = GameParticipantRegistry.get();
		GameParticipantRegistry.put(this);
		stateUpdate.setMessage("<b>" + (cause.getPlayer() == null ? "null" : cause.getPlayer().getName()) + "</b>: " + cause.getMessage());
		try {
			writeBean(stateUpdate);
		} finally {
			dictionary.update(gameServer.getGame());
			GameParticipantRegistry.put(old);
		}
	}

	public Player getPlayer() {
		return player;
	}

	public void notifyOfMeasure(voting.Measure m) {
		gameServer.notifyOfMeasure(m);
	}

	public void notifyOfVote(Player player, int vote) {
		gameServer.notifyOfVote(player, vote);
	}

	public void endGame(String winner) {
		gameServer.endGame(winner);
	}

	public String getModule() {
		return gameServer.getModule();
	}

	private final GameServer gameServer;
	private final Player player;
}